
<!DOCTYPE html>
<html lang="zh-cn">
    
<head>
    <meta http-equiv="Content-Type" content="text/html" charset="UTF-8" >
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="generator" content="XGHeaven&#39;s Blog">
    <title>Reflect-Metadata 详解 - XGHeaven&#39;s Blog</title>
    <meta name="author" content="XGHeaven">
    
    
    
        <link rel="alternate" type="application/atom+xml" title="RSS" href="/atom.xml">
    
    <meta name="description" content="引言在 ES6 的规范当中，就已经存在 Reflect API 了。简单来说这个 API 的作用就是可以实现对变量操作的函数化，也就是反射。具体的关于这个 API 的内容，可以查看这个教程 然而我们在这里讲到的，却是 Reflect 里面还没有的一个规范，那么就是 Reflect Metadata。 Metadata想必对于其他语言的 Coder 来说，比如说 Java 或者 C#，Metadat">
<meta name="keywords" content="Javascript,Reflect Metadata">
<meta property="og:type" content="blog">
<meta property="og:title" content="Reflect-Metadata 详解">
<meta property="og:url" content="http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/index.html">
<meta property="og:site_name" content="XGHeaven&#39;s Blog">
<meta property="og:description" content="引言在 ES6 的规范当中，就已经存在 Reflect API 了。简单来说这个 API 的作用就是可以实现对变量操作的函数化，也就是反射。具体的关于这个 API 的内容，可以查看这个教程 然而我们在这里讲到的，却是 Reflect 里面还没有的一个规范，那么就是 Reflect Metadata。 Metadata想必对于其他语言的 Coder 来说，比如说 Java 或者 C#，Metadat">
<meta property="og:locale" content="zh-cn">
<meta property="og:updated_time" content="2017-12-30T14:49:40.028Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Reflect-Metadata 详解">
<meta name="twitter:description" content="引言在 ES6 的规范当中，就已经存在 Reflect API 了。简单来说这个 API 的作用就是可以实现对变量操作的函数化，也就是反射。具体的关于这个 API 的内容，可以查看这个教程 然而我们在这里讲到的，却是 Reflect 里面还没有的一个规范，那么就是 Reflect Metadata。 Metadata想必对于其他语言的 Coder 来说，比如说 Java 或者 C#，Metadat">
<meta name="twitter:creator" content="@XGHeaven">
    
    
        
    
    
        <meta property="og:image" content="https://www.gravatar.com/avatar/f34474afe04544ffbe944a804f0ae762?s=640"/>
    
    
    
    
    <!--STYLES-->
    <link rel="stylesheet" href="/assets/css/style-mhhgzztqkaub4zd4cl8bd83f7mgh9j6njnhilft4hamhrjsliqyzwo2cfzdk.min.css">
    <!--STYLES END-->
    
    <script type="text/javascript">
        var _gaq = _gaq || [];
        _gaq.push(['_setAccount', 'UA-71388235-1']);
        _gaq.push(['_trackPageview']);
        (function() {
            var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
            ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
            var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
        })();
    </script>

    
    <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "//hm.baidu.com/hm.js?9894361f828b64144ac1f2ac0c58c300";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
    </script>

</head>

    <body>
        <div id="blog">
            <!-- Define author's picture -->


    
        
    

<header id="header" data-behavior="3">
    <i id="btn-open-sidebar" class="fa fa-lg fa-bars"></i>
    <h1 class="header-title">
        <a class="header-title-link" href="/ ">XGHeaven&#39;s Blog</a>
    </h1>
    
        
            <a  class="header-right-picture "
                href="#about">
        
        
            <img class="header-picture" src="https://www.gravatar.com/avatar/f34474afe04544ffbe944a804f0ae762?s=90"/>
        
        </a>
    
</header>
            <!-- Define author's picture -->


    

<nav id="sidebar" data-behavior="3">
    
        <div class="sidebar-profile">
            <a href="/#about">
                    <img class="sidebar-profile-picture" src="https://www.gravatar.com/avatar/f34474afe04544ffbe944a804f0ae762?s=110"/>
            </a>
            <span class="sidebar-profile-name">XGHeaven</span>
        </div>
    
    
        <ul class="sidebar-buttons">
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="/ "
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-home"></i>
                    <span class="sidebar-button-desc">首页</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="/all-categories"
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-bookmark"></i>
                    <span class="sidebar-button-desc">分类</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="/all-tags"
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-tags"></i>
                    <span class="sidebar-button-desc">标签</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="/all-archives"
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-archive"></i>
                    <span class="sidebar-button-desc">归档</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="#about"
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-question"></i>
                    <span class="sidebar-button-desc">关于</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="/friend-link"
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-link"></i>
                    <span class="sidebar-button-desc">友情链接</span>
                </a>
        </li>
        
    </ul>
    
        <ul class="sidebar-buttons">
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link " href="https://github.com/XGHeaven" target="_blank">
                
                    <i class="sidebar-button-icon fa fa-lg fa-github"></i>
                    <span class="sidebar-button-desc">GitHub</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link " href="https://twitter.com/xgheaven" target="_blank">
                
                    <i class="sidebar-button-icon fa fa-lg fa-twitter"></i>
                    <span class="sidebar-button-desc">Twitter</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link " href="https://facebook.com/xgheaven" target="_blank">
                
                    <i class="sidebar-button-icon fa fa-lg fa-facebook"></i>
                    <span class="sidebar-button-desc">Facebook</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link " href="https://www.linkedin.com/xgheaven/" target="_blank">
                
                    <i class="sidebar-button-icon fa fa-lg fa-linkedin"></i>
                    <span class="sidebar-button-desc">LinkedIn</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link " href="mailto:xgheaven@gmail.com" target="_blank">
                
                    <i class="sidebar-button-icon fa fa-lg fa-envelope-o"></i>
                    <span class="sidebar-button-desc">邮箱</span>
                </a>
        </li>
        
    </ul>
    
        <ul class="sidebar-buttons">
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="/atom.xml"
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-rss"></i>
                    <span class="sidebar-button-desc">RSS</span>
                </a>
        </li>
        
            <li class="sidebar-button">
                
                    <a  class="sidebar-button-link "
                         href="/changelog"
                        
                    >
                
                    <i class="sidebar-button-icon fa fa-lg fa-line-chart"></i>
                    <span class="sidebar-button-desc">Changelog</span>
                </a>
        </li>
        
    </ul>
    
</nav>

            
            <div id="main" data-behavior="3"
                 class="
                        hasCoverMetaIn
                        ">
                
<article class="post" itemscope itemType="http://schema.org/BlogPosting">
    
    
        <div class="post-header main-content-wrap text-left">
    
        <h1 class="post-title" itemprop="headline">
            Reflect-Metadata 详解
        </h1>
    
    <div class="post-meta">
    <time itemprop="datePublished" content="Sat Dec 30 2017 22:44:07 GMT+0800">
	
		    12月 30, 2017
    	
    </time>
    
        <span>发布在 </span>
        
    <a class="category-link" href="/categories/Jacascript/">Jacascript</a>


    
</div>
</div>
    
    <div class="post-content markdown" itemprop="articleBody">
        <div class="main-content-wrap">
            <h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>在 ES6 的规范当中，就已经存在 <code>Reflect</code> API 了。简单来说这个 API 的作用就是可以实现对变量操作的函数化，也就是反射。具体的关于这个 API 的内容，可以查看这个<a href="http://es6.ruanyifeng.com/#docs/reflect" target="_blank" rel="external">教程</a></p>
<p>然而我们在这里讲到的，却是 <code>Reflect</code> 里面还没有的一个规范，那么就是 <code>Reflect Metadata</code>。</p>
<h2 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h2><p>想必对于其他语言的 Coder 来说，比如说 Java 或者 C#，Metadata 是很熟悉的。最简单的莫过于通过反射来获取类属性上面的批注（在 JS 当中，也就是所谓的装饰器）。从而可以更加优雅的对代码进行控制。</p>
<p>而 JS 现在有<a href="https://github.com/tc39/proposal-decorators" target="_blank" rel="external">装饰器</a>，虽然现在还在 <code>Stage2</code> 阶段。但是 JS 的装饰器更多的是存在于对函数或者属性进行一些操作，比如修改他们的值，代理变量，自动绑定 this 等等功能。</p>
<blockquote>
<p>所以，后文当中我就使用 TypeScript 来进行讲解，因为 TypeScript 已经完整的实现了装饰器。<br>虽然 Babel 也可以，但是需要各种配置，人懒，不想配置那么多。</p>
</blockquote>
<p>但是却无法实现通过反射来获取究竟有哪些装饰器添加到这个类/方法上。</p>
<p>于是 <code>Reflect Metadata</code> 应运而生。</p>
<h2 id="Reflect-Metadata"><a href="#Reflect-Metadata" class="headerlink" title="Reflect Metadata"></a>Reflect Metadata</h2><p>Relfect Metadata，简单来说，你可以通过装饰器来给类添加一些自定义的信息。然后通过反射将这些信息提取出来。当然你也可以通过反射来添加这些信息。 就像是下面这个例子所示。</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Reflect</span>.metadata(<span class="string">'name'</span>, <span class="string">'A'</span>)</div><div class="line"><span class="keyword">class</span> A &#123;</div><div class="line">  <span class="meta">@Reflect</span>.metadata(<span class="string">'hello'</span>, <span class="string">'world'</span>)</div><div class="line">  <span class="keyword">public</span> hello(): <span class="built_in">string</span> &#123;</div><div class="line">    <span class="keyword">return</span> <span class="string">'hello world'</span></div><div class="line">  &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">Reflect.getMetadata(<span class="string">'name'</span>, A) <span class="comment">// 'A'</span></div><div class="line">Reflect.getMetadata(<span class="string">'hello'</span>, <span class="keyword">new</span> A()) <span class="comment">// 'world'</span></div><div class="line"><span class="comment">// 这里为什么要用 new A()，用 A 不行么？后文会讲到</span></div></pre></td></tr></table></figure>
<p>是不是很简单，那么我简单来介绍一下~</p>
<h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>首先，在这里有四个概念要区分一下：</p>
<ol>
<li><code>Metadata Key</code> {Any} 后文简写 <code>k</code>。元数据的 Key，对于一个对象来说，他可以有很多元数据，每一个元数据都对应有一个 Key。一个很简单的例子就是说，你可以在一个对象上面设置一个叫做 <code>&#39;name&#39;</code> 的 Key 用来设置他的名字，用一个 <code>&#39;created time&#39;</code> 的 Key 来表示他创建的时间。这个 Key 可以是任意类型。在后面会讲到内部本质就是一个 <code>Map</code> 对象。</li>
<li><code>Metadata Value</code> {Any} 后文简写 <code>v</code>。元数据的类型，任意类型都行。</li>
<li><code>Target</code> {Object} 后文简写 <code>o</code>。表示要在这个对象上面添加元数据</li>
<li><code>Property</code> {String|Symbol} 后文简写 <code>p</code>。用于设置在那个属性上面添加元数据。大家可能会想，这个是干什么用的，不是可以在对象上面添加元数据了么？其实不仅仅可以在对象上面添加元数据，甚至还可以在对象的属性上面添加元数据。其实大家可以这样理解，当你给一个对象定义元数据的时候，相当于你是默认指定了 <code>undefined</code> 作为 Property。 下面有一个例子大家可以看一下。</li>
</ol>
<p>大家明白了上面的概念之后，我之前给的那个例子就很简单了~不用我多说了。</p>
<h3 id="安装-使用"><a href="#安装-使用" class="headerlink" title="安装/使用"></a>安装/使用</h3><p>下面不如正题，我们怎么开始使用 <code>Reflect Metadata</code> 呢？<br>首先，你需要安装 <code>reflect-metadata</code> polyfill，然后引入之后就可以看到在 <code>Reflect</code> 对象下面有很多关于 Metadata 的函数了。因为这个还没有进入正式的协议，所以需要安装垫片使用。</p>
<blockquote>
<p>啥，Reflect 是啥，一个全局变量而已。</p>
</blockquote>
<p>你不需要担心这个垫片的质量，因为连 Angular 都在使用呢，你怕啥。</p>
<p>之后你就可以安装我上面写的示例，在 TypeScript 当中去跑了。</p>
<h3 id="类-属性-方法-装饰器"><a href="#类-属性-方法-装饰器" class="headerlink" title="类/属性/方法 装饰器"></a>类/属性/方法 装饰器</h3><p>看这个例子。</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Reflect</span>.metadata(<span class="string">'name'</span>, <span class="string">'A'</span>)</div><div class="line"><span class="keyword">class</span> A &#123;</div><div class="line">  <span class="meta">@Reflect</span>.metadata(<span class="string">'name'</span>, <span class="string">'hello'</span>)</div><div class="line">  hello() &#123;&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">const</span> objs = [A, <span class="keyword">new</span> A, A.prototype]</div><div class="line"><span class="keyword">const</span> res = objs.map(<span class="function"><span class="params">obj</span> =&gt;</span> [</div><div class="line">  Reflect.getMetadata(<span class="string">'name'</span>, obj),</div><div class="line">  Reflect.getMetadata(<span class="string">'name'</span>, obj, <span class="string">'hello'</span>),</div><div class="line">  Reflect.getOwnMetadata(<span class="string">'name'</span>, obj),</div><div class="line">  Reflect.getOwnMetadata(<span class="string">'name'</span>, obj ,<span class="string">'hello'</span>)</div><div class="line">])</div><div class="line"><span class="comment">// 大家猜测一下 res 的值会是多少？</span></div></pre></td></tr></table></figure>
<blockquote>
<p>想好了么？再给你 10 秒钟</p>
<p>10<br>9<br>8<br>7<br>6<br>5<br>4<br>3<br>2<br>1</p>
</blockquote>
<p>res</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">[</div><div class="line">  [<span class="string">'A'</span>, <span class="literal">undefined</span>, <span class="string">'A'</span>, <span class="literal">undefined</span>],</div><div class="line">  [<span class="literal">undefined</span>, <span class="string">'hello'</span>, <span class="literal">undefined</span>, <span class="literal">undefined</span>],</div><div class="line">  [<span class="literal">undefined</span>, <span class="string">'hello'</span>, <span class="literal">undefined</span>, <span class="string">'hello'</span>],</div><div class="line">]</div></pre></td></tr></table></figure>
<p>那么我来解释一下为什么回是这样的结果。</p>
<p>首先所有的对类的修饰，都是定义在类这个对象上面的，而所有的对类的属性或者方法的修饰，都是定义在类的原型上面的，并且以属性或者方法的 key 作为 property，这也就是为什么 <code>getMetadata</code> 会产生这样的效果了。</p>
<p>那么带 <code>Own</code> 的又是什么情况呢？</p>
<p>这就要从元数据的查找规则开始讲起了</p>
<h3 id="原型链查找"><a href="#原型链查找" class="headerlink" title="原型链查找"></a>原型链查找</h3><p>类似于类的继承，查找元数据的方式也是通过原型链进行的。</p>
<p>就像是上面那个例子，我实例化了一个 <code>new A()</code>，但是我依旧可以找到他原型链上的元数据。</p>
<p>举个例子</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">class</span> A &#123;</div><div class="line">  <span class="meta">@Reflect</span>.metadata(<span class="string">'name'</span>, <span class="string">'hello'</span>)</div><div class="line">  hello() &#123;&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">const</span> t1 = <span class="keyword">new</span> A()</div><div class="line"><span class="keyword">const</span> t2 = <span class="keyword">new</span> A()</div><div class="line">Reflect.defineMetadata(<span class="string">'otherName'</span>, <span class="string">'world'</span>, t2, <span class="string">'hello'</span>)</div><div class="line">Reflect.getMetadata(<span class="string">'name'</span>, t1, <span class="string">'hello'</span>) <span class="comment">// 'hello'</span></div><div class="line">Reflect.getMetadata(<span class="string">'name'</span>, t2, <span class="string">'hello'</span>) <span class="comment">// 'hello'</span></div><div class="line">Reflect.getMetadata(<span class="string">'otherName'</span>, t2, <span class="string">'hello'</span>) <span class="comment">// 'world'</span></div><div class="line"></div><div class="line">Reflect.getOwnMetadata(<span class="string">'name'</span>, t2, <span class="string">'hello'</span>) <span class="comment">// undefined</span></div><div class="line">Reflect.getOwnMetadata(<span class="string">'otherName'</span>, t2, <span class="string">'hello'</span>) <span class="comment">// 'world'</span></div></pre></td></tr></table></figure>
<h3 id="用途"><a href="#用途" class="headerlink" title="用途"></a>用途</h3><p>其实所有的用途都是一个目的，给对象添加额外的信息，但是不影响对象的结构。这一点很重要，当你给对象添加了一个原信息的时候，对象是不会有任何的变化的，不会多 property，也不会有的 property 被修改了。<br>但是可以衍生出很多其他的用途。</p>
<ul>
<li>Anuglar 中对特殊字段进行修饰 (Input)，从而提升代码的可读性。</li>
<li>可以让装饰器拥有真正装饰对象而不改变对象的能力。让对象拥有更多语义上的功能。</li>
</ul>
<h3 id="API"><a href="#API" class="headerlink" title="API"></a>API</h3><figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">namespace</span> Reflect &#123;</div><div class="line">  <span class="comment">// 用于装饰器</span></div><div class="line">  metadata(k, v): <span class="function">(<span class="params">target, property?</span>) =&gt;</span> <span class="built_in">void</span></div><div class="line">  </div><div class="line">  <span class="comment">// 在对象上面定义元数据</span></div><div class="line">  defineMetadata(k, v, o, p?): <span class="built_in">void</span></div><div class="line">  </div><div class="line">  <span class="comment">// 是否存在元数据</span></div><div class="line">  hasMetadata(k, o, p?): <span class="built_in">boolean</span></div><div class="line">  hasOwnMetadata(k, o, p?): <span class="built_in">boolean</span></div><div class="line">  </div><div class="line">  <span class="comment">// 获取元数据</span></div><div class="line">  getMetadata(k, o, p?): <span class="built_in">any</span></div><div class="line">  getOwnMetadata(k, o, p?): <span class="built_in">any</span></div><div class="line">  </div><div class="line">  <span class="comment">// 获取所有元数据的 Key</span></div><div class="line">  getMetadataKeys(o, p?): <span class="built_in">any</span>[]</div><div class="line">  getOwnMetadataKeys(o, p?): <span class="built_in">any</span>[]</div><div class="line">  </div><div class="line">  <span class="comment">// 删除元数据</span></div><div class="line">  deleteMetadata(k, o, p?): <span class="built_in">boolean</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<blockquote>
<p>大家可能注意到，针对某些操作，会有 <code>Own</code> 的函数。这是因为有的操作是可以通过原型链进行操作的。这个后文讲解。</p>
</blockquote>
<h2 id="深入-Reflect-Metadata"><a href="#深入-Reflect-Metadata" class="headerlink" title="深入 Reflect Metadata"></a>深入 Reflect Metadata</h2><h3 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h3><p>如果你去翻看官网的文档，他会和你说，所有的元数据都是存在于对象下面的 <code>[[Metadata]]</code> 属性下面。一开始我也是这样认为的，新建一个 <code>Symbol(&#39;Metadata&#39;)</code>，然后将元数据放到这个 Symbol 对应的 Property 当中。直到我看了源码才发现并不是这样。请看例子</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Reflect</span>.metadata(<span class="string">'name'</span>, <span class="string">'A'</span>)</div><div class="line"><span class="keyword">class</span> A &#123;&#125;</div><div class="line"></div><div class="line"><span class="built_in">Object</span>.getOwnPropertySymbols(A) <span class="comment">// []</span></div></pre></td></tr></table></figure>
<p>哈哈，并没有所谓的 Symbol，那么这些元数据都存在在哪里呢？</p>
<p>其实是内部的一个 WeakMap 中。他正是利用了 WeakMap 不增加引用计数的特点，将对象作为 Key，元数据集合作为 Value，存到 WeakMap 中去。</p>
<p>如果你认真探寻的话，你会发现其内部的数据结构其实是这样的</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">WeakMap&lt;<span class="built_in">any</span>, Map&lt;<span class="built_in">any</span>, Map&lt;<span class="built_in">any</span>, <span class="built_in">any</span>&gt;&gt;&gt;</div></pre></td></tr></table></figure>
<p>是不是超级绕，但是我们从调用的角度来思考，这就一点都不绕了。</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">weakMap.get(o).get(p).get(k)</div></pre></td></tr></table></figure>
<p>先根据对象获取，然后在根据属性，最后根据元数据的 Key 获取最终要的数据。</p>
<h2 id="End"><a href="#End" class="headerlink" title="End"></a>End</h2><p>因为 Reflect Metadata 实在是比较简单，这里就不多讲解了。更多内容请查看 <a href="https://rbuckton.github.io/reflect-metadata" target="_blank" rel="external">Spec</a></p>
<h2 id="题外话"><a href="#题外话" class="headerlink" title="题外话"></a>题外话</h2><p>其实看了源码之后还是挺惊讶的，按照一般的套路，很多 polyfill 会让你提供一些前置的 polyfill 之后，当前的 polyfill 才能使用。但是 <code>reflect-metadata</code> 竟然内部自己实现了很多的 polyfill 和算法。比如 Map, Set, WeakMap, UUID。最惊讶的莫过于 WeakMap 了。不是很仔细的阅读了一下，好像还是会增加引用计数。</p>

            
                

            
        </div>
    </div>
    <div id="post-footer" class="post-footer main-content-wrap">
        
            <div class="post-footer-tags">
                <span class="text-color-light text-small">标签</span><br/>
                
    <a class="tag tag--primary tag--small t-link" href="/tags/Javascript/">Javascript</a> <a class="tag tag--primary tag--small t-link" href="/tags/Reflect-Metadata/">Reflect Metadata</a>

            </div>
        
        <div class="post-actions-wrap">
    <nav>
        <ul class="post-actions post-action-nav">
            <li class="post-action">
                
                    <a class="post-action-btn btn btn--default tooltip--top" href="/2018/02/16/summary-2018/"  data-tooltip="2018 年终总结">
                
                    <i class="fa fa-angle-left"></i>
                    <span class="hide-xs hide-sm text-small icon-ml">上一篇</span>
                </a>
            </li>
            <li class="post-action">
                
                    <a class="post-action-btn btn btn--default tooltip--top" href="/2017/08/17/vue-lever-a-plugin-help-you-to-manager-true-false-state/" data-tooltip="Vue-Lever 一个使用装饰器模式的插件帮你管理 True/false 状态">
                
                    <span class="hide-xs hide-sm text-small icon-mr">下一篇</span>
                    <i class="fa fa-angle-right"></i>
                </a>
            </li>
        </ul>
    </nav>
    <ul class="post-actions post-action-share">
        <li class="post-action hide-lg hide-md hide-sm">
            <a class="post-action-btn btn btn--default btn-open-shareoptions"  href="#btn-open-shareoptions">
                <i class="fa fa-share-alt"></i>
            </a>
        </li>
        <li class="post-action hide-xs">
            <a class="post-action-btn btn btn--default" target="new" href="https://plus.google.com/share?url=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-google-plus"></i>
            </a>
        </li>
        <li class="post-action hide-xs">
            <a class="post-action-btn btn btn--default" target="new" href="https://www.facebook.com/sharer/sharer.php?u=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-facebook-official"></i>
            </a>
        </li>
        <li class="post-action hide-xs">
            <a class="post-action-btn btn btn--default" target="new" href="https://twitter.com/intent/tweet?text=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-twitter"></i>
            </a>
        </li>
        
            <li class="post-action">
                <a class="post-action-btn btn btn--default" href="#disqus_thread">
                    <i class="fa fa-comment-o"></i>
                </a>
            </li>
        
        <li class="post-action">
            
                <a class="post-action-btn btn btn--default" href="#">
            
                <i class="fa fa-list"></i>
            </a>
        </li>
    </ul>
</div>


        
            
                <div id="disqus_thread">
    <noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
            
        
    </div>
</article>



                <footer id="footer" class="main-content-wrap">
    <span class="copyrights">
        Copyrights &copy; 2018 XGHeaven. All Rights Reserved.
    </span>
</footer>

            </div>
            
                <div id="bottom-bar" class="post-bottom-bar" data-behavior="3">
                    <div class="post-actions-wrap">
    <nav>
        <ul class="post-actions post-action-nav">
            <li class="post-action">
                
                    <a class="post-action-btn btn btn--default tooltip--top" href="/2018/02/16/summary-2018/"  data-tooltip="2018 年终总结">
                
                    <i class="fa fa-angle-left"></i>
                    <span class="hide-xs hide-sm text-small icon-ml">上一篇</span>
                </a>
            </li>
            <li class="post-action">
                
                    <a class="post-action-btn btn btn--default tooltip--top" href="/2017/08/17/vue-lever-a-plugin-help-you-to-manager-true-false-state/" data-tooltip="Vue-Lever 一个使用装饰器模式的插件帮你管理 True/false 状态">
                
                    <span class="hide-xs hide-sm text-small icon-mr">下一篇</span>
                    <i class="fa fa-angle-right"></i>
                </a>
            </li>
        </ul>
    </nav>
    <ul class="post-actions post-action-share">
        <li class="post-action hide-lg hide-md hide-sm">
            <a class="post-action-btn btn btn--default btn-open-shareoptions"  href="#btn-open-shareoptions">
                <i class="fa fa-share-alt"></i>
            </a>
        </li>
        <li class="post-action hide-xs">
            <a class="post-action-btn btn btn--default" target="new" href="https://plus.google.com/share?url=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-google-plus"></i>
            </a>
        </li>
        <li class="post-action hide-xs">
            <a class="post-action-btn btn btn--default" target="new" href="https://www.facebook.com/sharer/sharer.php?u=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-facebook-official"></i>
            </a>
        </li>
        <li class="post-action hide-xs">
            <a class="post-action-btn btn btn--default" target="new" href="https://twitter.com/intent/tweet?text=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-twitter"></i>
            </a>
        </li>
        
            <li class="post-action">
                <a class="post-action-btn btn btn--default" href="#disqus_thread">
                    <i class="fa fa-comment-o"></i>
                </a>
            </li>
        
        <li class="post-action">
            
                <a class="post-action-btn btn btn--default" href="#">
            
                <i class="fa fa-list"></i>
            </a>
        </li>
    </ul>
</div>


                </div>
                <div id="share-options-bar" class="share-options-bar" data-behavior="3">
    <ul class="share-options">
        <li class="share-option">
            <a class="share-option-btn" target="new" href="https://plus.google.com/share?url=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-google-plus"></i><span class="">分享到 Google+</span>
            </a>
        </li>
        <li class="share-option">
            <a class="share-option-btn" target="new" href="https://www.facebook.com/sharer/sharer.php?u=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-facebook-official"></i><span>分享到 Facebook</span>
            </a>
        </li>
        <li class="share-option">
            <a class="share-option-btn" target="new" href="https://twitter.com/intent/tweet?text=http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/">
                <i class="fa fa-twitter"></i><span>分享到 Twitter</span>
            </a>
        </li>
    </ul>
</div>
<div id="share-options-mask" class="share-options-mask"></div>
            
        </div>
        


    

<div id="about">
    <div id="about-card">
        <div id="about-btn-close">
            <i class="fa fa-remove"></i>
        </div>
        
            <img id="about-card-picture" src="https://www.gravatar.com/avatar/f34474afe04544ffbe944a804f0ae762?s=110"/>
        
            <h4 id="about-card-name">XGHeaven</h4>
        
            <h5 id="about-card-bio"><p>一个弱弱的码农</p>
</h5>
        
        
            <h5 id="about-card-job">
                <i class="fa fa-briefcase"></i>
                <br/>
                <p>杭州电子科技大学学生一枚</p>

            </h5>
        
        
            <h5 id="about-card-location">
                <i class="fa fa-map-marker"></i>
                <br/>
                Weifang Shandong, China
            </h5>
        
    </div>
</div>

        
<div id="cover" style="background-image:url('/static/images/20170217-TombRaider.jpg');"></div>
    </body>
    <!--SCRIPTS-->
<script src="/assets/js/scrip-z6xcdnzggiy56kzp83ux5nnbwra1acrauxruz3kdi3u5xladb6jh4n3ylebm.min.js"></script>
<!--SCRIPTS END-->

    
        <script>
             var disqus_config = function () {
                 this.page.url = 'http://blog.xgheaven.cn/2017/12/30/Reflect-metadata/';
                 
                    this.page.identifier = '2017/12/30/Reflect-metadata/';
                                  
             };
            (function() {
                var d = document, s = d.createElement('script');
                var disqus_shortname = 'xgheaven-blog';
                s.src = 'https://' + disqus_shortname + '.disqus.com/embed.js';

                s.setAttribute('data-timestamp', +new Date());
                (d.head || d.body).appendChild(s);
            })();
        </script>
    



</html>
